home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************************/
- /* */
- /* SimpleCSClock - A simple control strip clock module */
- /* */
- /* By Mike Blackwell, mkb@cs.cmu.edu */
- /* */
- /****************************************************************************************/
-
- #include <GestaltEqu.h>
- #include <Fonts.h>
- #include <Memory.h>
- #include <Packages.h>
- #include <Resources.h>
- #include <Strings.h>
- #include <SysEqu.h>
- #include <ToolUtils.h>
- #include "ControlStrip.h"
- #include "SimpleCSClock.h"
-
-
- // How often to check if the display needs to be updated (in ticks)
- #define INTERVAL (2 * 60) // 2 seconds
-
- // Display font information
- #define DISPLAY_FONT monaco
- #define DISPLAY_FONT_SIZE 9
- #define DISPLAY_FONT_FACE 0
- #define DISPLAY_MARGIN 3 // Blank space to left and right of text
-
- typedef struct Globals {
- PicHandle arrowPicture; // Picture to show we have a popup menu
- short arrowWidth, arrowHeight; // Size of arrow
- short fontHeight; // Ascender height of display font
- Handle helpStrings; // Balloon help strings for each state
- MenuHandle configMenu; // Menu to select display options
- int width; // Width of display
- Boolean show12Hour; // True for 12 hour display
- int displayTime; // Time that is currently being displayed
- // (in minutes since midnight)
- unsigned long nextTick; // When to next update the display
- } Globals, *GlobalPtr, **GlobalHandle;
-
-
- typedef struct SavedSettings {
- OSType signature; // Signature to verify that prefs are for
- // this module
- Boolean show12Hour; // True for 12 hour display
- } SavedSettings;
-
-
- long Initialize(void);
- void CleanUp(GlobalHandle globHand);
- long HandleMouseClick(GlobalPtr globPtr, Rect *statusRect);
- short SavePreferences(GlobalPtr globPtr);
- Boolean UpdateTime(GlobalPtr globPtr);
- int DrawDisplay(GlobalPtr globPtr, Rect *statusRect, Boolean drawit);
- Boolean CheckFeatures(void);
-
-
- pascal long main(long message, long params, Rect *statusRect, GrafPtr statusPort)
- {
- #pragma unused(statusPort)
- char savedState;
- GlobalPtr globPtr;
- long result;
- int current_width;
- Str255 helpString;
-
- if (params > 0) { // If we have globals allocated,
- savedState = HGetState((Handle)params); // save the locked/unlocked state,
- HLock((Handle)params); // lock the handle to the globals,
- globPtr = *(GlobalHandle)params; // and point to globals directly
- }
-
- result = 0; // Return zero for unknown messages
-
- switch (message) {
-
- case sdevInitModule: // Initialize the module
- result = Initialize();
- break;
-
- case sdevCloseModule: // Clean up before being closed
- CleanUp((GlobalHandle)params);
- params = 0L; // Handle is gone now
- break;
-
- case sdevFeatures: // Return feature bits
- result = (1 << sdevWantMouseClicks) | \
- (1 << sdevDontAutoTrack) | \
- (1 << sdevHasCustomHelp);
- break;
-
- case sdevGetDisplayWidth: // Return display width
- result = globPtr->width;
- break;
-
- case sdevPeriodicTickle: // Periodic tickle when nothing else is happening
- if (TickCount() >= globPtr->nextTick) { // Time to update display yet?
- if (UpdateTime(globPtr)) { // Check if time has changed
- EraseRect(statusRect); // Yep, erase the old
- current_width = DrawDisplay(globPtr, statusRect, true); // And draw the new
- // If the display width changed, let the control strip know
- if (globPtr->width != current_width) {
- globPtr->width = current_width;
- result = (1 << sdevResizeDisplay);
- }
- }
- globPtr->nextTick = TickCount() + INTERVAL;
- }
- break;
-
- case sdevDrawStatus: // Update the display
- (void)DrawDisplay(globPtr, statusRect, true);
- break;
-
- case sdevMouseClick: // User clicked on the module's display area in the status bar
- result = HandleMouseClick(globPtr, statusRect);
- break;
-
- case sdevSaveSettings: // Save changed settings
- result = SavePreferences(globPtr);
- break;
-
- case sdevShowBalloonHelp: // Display custom balloon help
- SBGetDetachedIndString(&helpString, globPtr->helpStrings,
- globPtr->show12Hour ? kHelp12StringStr : kHelp24StringStr);
- SBShowHelpString(statusRect, &helpString);
- break;
- }
-
- if ((long)params > 0) // If we have globals allocated,
- HSetState((Handle)params, savedState); // restore the locked/unlocked state
-
- return(result);
- }
-
-
- long Initialize(void)
- {
- long result;
- GlobalPtr globPtr;
- GlobalHandle globHand;
- FontInfo fontInfo;
- Str255 prefsResourceName;
- SavedSettings **preferences;
-
- result = -1; // Assume failure
-
- if (!CheckFeatures()) return(result);
-
- if (! (globHand = (GlobalHandle)NewHandleClear(sizeof(Globals))))
- goto done; // Allocate the globals
-
- HLock((Handle)globHand); // Lock the globals while using them
- globPtr = *globHand; // and get a pointer to them
-
- // Load and detach the ‘up arrow’ picture
-
- if (! (globPtr->arrowPicture = GetPicture(kArrowPictID))) goto done;
- DetachResource((Handle)globPtr->arrowPicture);
-
- // Compute size of arrow picture
-
- globPtr->arrowHeight = (**globPtr->arrowPicture).picFrame.bottom -
- (**globPtr->arrowPicture).picFrame.top;
- globPtr->arrowWidth = (**globPtr->arrowPicture).picFrame.right -
- (**globPtr->arrowPicture).picFrame.left;
-
- // Compute size of display font
-
- TextFont(DISPLAY_FONT);
- TextSize(DISPLAY_FONT_SIZE);
- TextFace(DISPLAY_FONT_FACE);
- GetFontInfo(&fontInfo);
- globPtr->fontHeight = fontInfo.ascent;
-
- // Load and detach the configuration menu
-
- if (! (globPtr->configMenu = GetMenu(kConfigMenuID))) goto done;
- DetachResource((Handle)globPtr->configMenu);
-
- // Load and detach the help strings
-
- if (! (globPtr->helpStrings = Get1Resource('STR#', kHelpStringsID))) goto done;
- DetachResource(globPtr->helpStrings);
-
- // Get the module's saved preferences, if any, and configure the module
-
- SBGetDetachedIndString(&prefsResourceName, globPtr->helpStrings, kPrefNameStr);
- if (! SBLoadPreferences(&prefsResourceName, (Handle *)&preferences) &&
- ((**preferences).signature == kSignature)) {
- globPtr->show12Hour = (**preferences).show12Hour;
- }
-
- globPtr->nextTick = 0; // Do first update right away
- globPtr->width = 0;
- globPtr->displayTime = 0; // Haven't displayed a time yet
-
- HUnlock((Handle)globHand); // Unlock the globals
-
- result = (long)globHand; // Return the handle to the globals as the result
-
- done:
- return(result); // Return either a handle or an error code
- }
-
-
- void CleanUp(GlobalHandle globHand)
- {
- GlobalPtr globPtr;
-
- if ((long)globHand <= 0) return;
-
- HLock((Handle)globHand);
- globPtr = *globHand;
-
- if (globPtr->arrowPicture) DisposeHandle((Handle)globPtr->arrowPicture);
-
- if (globPtr->configMenu) DisposeMenu(globPtr->configMenu);
-
- if (globPtr->helpStrings) DisposeHandle(globPtr->helpStrings);
-
- DisposeHandle((Handle)globHand);
- }
-
-
- long HandleMouseClick(GlobalPtr globPtr, Rect *statusRect)
- {
- short menuItem;
- long result;
- int new_width;
- Boolean mode_changed;
-
- // Check off the appropriate items in the popup menu
-
- if (globPtr->show12Hour) {
- SetItemMark(globPtr->configMenu, k12HourCmd, sdevMenuItemMark);
- SetItemMark(globPtr->configMenu, k24HourCmd, noMark);
- } else {
- SetItemMark(globPtr->configMenu, k24HourCmd, sdevMenuItemMark);
- SetItemMark(globPtr->configMenu, k12HourCmd, noMark);
- }
-
- result = 0;
-
- // Display the popup menu
-
- menuItem = SBTrackPopupMenu(statusRect, globPtr->configMenu);
-
- // Handle the menu selection
-
- mode_changed = false;
-
- switch (menuItem) {
- case k12HourCmd:
- if (!globPtr->show12Hour) {
- globPtr->show12Hour = true;
- mode_changed = true;
- }
- break;
-
- case k24HourCmd:
- if (globPtr->show12Hour) {
- globPtr->show12Hour = false;
- mode_changed = true;
- }
- break;
- }
-
- // If the mode changed, calculate new display width and let CS know what happened
-
- if (mode_changed) {
- result = (1 << sdevNeedToSave) | (1 << sdevHelpStateChange);
- new_width = DrawDisplay(globPtr, statusRect, false);
- if (globPtr->width != new_width) {
- globPtr->width = new_width;
- result |= (1 << sdevResizeDisplay);
- }
- }
-
- return(result);
- }
-
-
- short SavePreferences(GlobalPtr globPtr)
- {
- short result;
- SavedSettings **preferences;
- Str255 prefsResourceName;
-
- preferences = (SavedSettings**)NewHandle(sizeof(SavedSettings));
-
- if (! (result = MemError())) { // Allocate a block to hold the settings
-
- (**preferences).signature = kSignature; // Include a signature to verify it's ours
- (**preferences).show12Hour = globPtr->show12Hour;
-
- // Get the name of the preferences resource
- SBGetDetachedIndString(prefsResourceName, globPtr->helpStrings, kPrefNameStr);
-
- // Save the settings in the Control Strip's preferences file
- result = SBSavePreferences(prefsResourceName, (Handle)preferences);
-
- DisposeHandle((Handle)preferences); // Get rid of the block
- }
-
- return(result);
- }
-
-
- // Compute the current time in seconds since midnight. If it's changed since we
- // last displayed the time, return true.
-
- Boolean UpdateTime(GlobalPtr globPtr)
- {
- unsigned long now;
- int dispTime;
-
- GetDateTime(&now); // Get seconds since epoch
- dispTime = (now % (60 * 60 * 24)) / 60; // Compute minutes since midnight
- if (dispTime != globPtr->displayTime) { // Has the time changed yet?
- globPtr->displayTime = dispTime; // Yes
- return(true); // Need to update display
- } else {
- return(false);
- }
- }
-
-
- // Stuff the ascii string representing the number in to the destination string.
- // Number range is 0 - 99. If pad is true, pad with a zero if necessary.
- // Return pointer to end of string.
-
- char *NumStr(char *dest, int num, Boolean pad)
- {
- if (num < 0) num = 0;
- if (num > 99) num = 99;
- if (num >= 10) {
- *dest++ = (num / 10) + '0';
- num %= 10;
- } else if (pad) {
- *dest++ = '0';
- }
- *dest++ = num + '0';
- *dest = '\0';
- return(dest);
- }
-
-
- // Draw the time specified in displayTime. If drawit is false, don't actually
- // do any drawing. Returns the width of the display
-
- int DrawDisplay(GlobalPtr globPtr, Rect *statusRect, Boolean drawit)
- {
- int result;
- char buf[10], *bptr;
- int hours, minutes;
- Boolean afternoon;
- int width, offset;
- Rect arrowRect;
-
- result = 0;
-
- hours = globPtr->displayTime / 60;
- if (globPtr->show12Hour) {
- afternoon = (hours >= 12);
- if (afternoon) hours -= 12;
- if (hours == 0) hours = 12;
- }
- minutes = globPtr->displayTime % 60;
-
- bptr = buf;
-
- if (globPtr->show12Hour) {
- bptr = NumStr(bptr, hours, false);
- *bptr++ = ':';
- bptr = NumStr(bptr, minutes, true);
- *bptr++ = (afternoon) ? 'P' : 'A';
- *bptr++ = 'M';
- *bptr = '\0';
- } else {
- bptr = NumStr(bptr, hours, true);
- *bptr++ = ':';
- bptr = NumStr(bptr, minutes, true);
- *bptr = '\0';
- }
- c2pstr(buf);
-
- // Draw the time string a little away from the right edge and centered vertically
- // Compute top/bottom margin. -1 is tweak to make it look just right...
- TextFont(DISPLAY_FONT);
- TextSize(DISPLAY_FONT_SIZE);
- TextFace(DISPLAY_FONT_FACE);
- if (drawit) {
- offset = (statusRect->bottom - statusRect->top - globPtr->fontHeight) / 2 - 1;
- MoveTo(statusRect->left + DISPLAY_MARGIN, statusRect->top + offset + globPtr->fontHeight);
- DrawString(buf);
- }
-
- width = DISPLAY_MARGIN + StringWidth(buf) - 1;
-
- // Draw the right arrow to show that the module has a popup menu
- if (drawit) {
- arrowRect.left = statusRect->left + width;
- arrowRect.right = arrowRect.left + globPtr->arrowWidth;
- arrowRect.top = statusRect->top +
- (statusRect->bottom - statusRect->top - globPtr->arrowHeight) / 2;
- arrowRect.bottom = arrowRect.top + globPtr->arrowHeight;
- DrawPicture(globPtr->arrowPicture, &arrowRect);
- }
-
- width += globPtr->arrowWidth;
-
- return(width);
- }
-
-
- // Check if this machine is capable of running this control strip (probably
- // by using Gestalt). This simple example will run on any Mac, so just return
- // true.
-
- Boolean CheckFeatures(void)
- {
- return(true);
- }
-